package ucalgary.seng401.tss;

public class TSSArchitecture {
	SysClock sysClock; 
	CallRecord[] callRecordsArray; 
	LineScanner[] lineScannerArray;
	CallProcessor callProcessor;
	
	private static final int NUM_LINES = 15;
	
	// process priorities 
	private final int SystemInitialPC_priority = 1; 
	private final int CallOriginationPC_priority = 1; 
	private final int DialingPC_priority = 1; 
	private final int CheckCalledStatusPC_priority = 1; 
	private final int ConnectingPC_priority = 1; 
	private final int TalkingPC_priority = 1; 
	private final int CallTerminationPC_priority = 1; 
	private final int ExceptionalTermination_priority = 1; 
	private final int LineScanningPC_priority = 3; 
	private final int SysClockPC_priority = 4; 
	private final int DigitsReceivingPC = 4; 
	
	
	public TSSArchitecture() {
		this.sysClock = new SysClock();
		this.callRecordsArray =  new CallRecord[16];
		for (int i = 0; i < callRecordsArray.length; i++)
			callRecordsArray[i] = new CallRecord();
		this.lineScannerArray = new LineScanner[16];
		for (int i = 0; i < lineScannerArray.length; i++)
			lineScannerArray[i] = new LineScanner();
		
	}
	
	// STATIC BEHAVIORS (SysSupportProcessesPC) 
	
	/** initialize control models
	 * 	set system clock
	 * 	set current time 
	 * 	set system clock interrupt counter 
	 */
	public void SysInitialPC() { 
		sysClock.t = 0; 
		sysClock.setCurrentTime(sysClock.getCurrentTime().getHours(), sysClock.getCurrentTime().getMinutes(), sysClock.getCurrentTime().getSeconds()); // SysClock.CurrentTime = 
		sysClock.setInterruptCounter(sysClock.getInterruptCounter() + 1); // SysClock.InterruptCounter = 0
	}
	
	/** 
	 * Monitor all LineScanners and update their logical states (idle, hook-on, hook-off, busy and invalid)
	 */
	public void LineScanningPC() { 
		System.out.println("  Running LineScanningPC"); 
		for (int i = 0; i < NUM_LINES; i++) { 
			if (lineScannerArray[i].CurrentScan == true && lineScannerArray[i].LastScan == false) {
				if (lineScannerArray[i].Status != 4 && lineScannerArray[i].Status != 5) // Not seized or invalid 
					lineScannerArray[i].Status = 0; // Set idle
			}
			else if (lineScannerArray[i].CurrentScan == false && lineScannerArray[i].LastScan == true) {
				lineScannerArray[i].Status = 1; // Set hook-on
			}
			else if (lineScannerArray[i].CurrentScan == true && lineScannerArray[i].LastScan == false) {
				lineScannerArray[i].Status = 2; // Set hook-off
				if (lineScannerArray[i].Status != 4) // Not a seized line 
					callRecordsArray[i].setCallProcess(1); // Call origination
				else 
					callRecordsArray[i].setCallProcess(0); // Called, no dispatch 
			}
			else if (lineScannerArray[i].CurrentScan == true && lineScannerArray[i].LastScan == true) {
				lineScannerArray[i].Status = 3; // Set busy 
			}
			else {
			}
			
		}
	}
	
	/**
	 * Update absolute (calendar) clock and relative clock for the system
	 * Updates all timers in call records 
	 */
	public void SysClockPC() { 
		System.out.println("  Running SysClockPC"); 
		sysClock.incrementInterruptCounter();
		if (sysClock.getInterruptCounter() == 999) { 
			sysClock.setInterruptCounter(0); 
			sysClock.incrementT();
			sysClock.updateCurrentTime(); 
			for (CallRecord c : callRecordsArray) { 
				if (c.isCallStatus() == true && c.getTimer()!= 0) 
					c.decrementTimer(); 
			}
			if (sysClock.getCurrentTime().getHours() == 23 && 
					sysClock.getCurrentTime().getMinutes() == 59 &&
					sysClock.getCurrentTime().getSeconds() == 59) { 
				sysClock.setCurrentTime(0, 0, 0); 
				sysClock.setT(0); 
			}
		}
	}
	
	/** 
	 * Receives called subscriber number sent by calling subscriber 
	 */
	public void DigitsReceivingPC() { 
		System.out.println("  Running DigitsReceivingPC"); 
	}
	
	// STATIC BEHAVIORS (CallingProcessingProcessesPC)
	
	/**
	 * Finds hook-off subscribes from LineScannersST
	 * Registers new originated calls in CallRecordST 
	 * @param lineNum
	 * @return CallProcess 
	 */
	public int CallOriginationPC(int lineNum) { 
		lineScannerArray[lineNum].Status = 3; // show line is busy 
		ConnectDrivePC(lineNum, 0, true);
		callRecordsArray[lineNum].setTimer(5); // set no dial timer 
		callRecordsArray[lineNum].setCallStatus(true); // set call record active 
		callRecordsArray[lineNum].setCallProcess(2); // to dialing 
		return callRecordsArray[lineNum].getCallProcess(); 
	}

	
	/** 
	 * Send dial tone to the subscriber which originated a new call
	 * @param subscriberLine
	 * @param dialTone
	 * @param on
	 */
	public void ConnectDrivePC(int subscriberLine, int dialTone, boolean on) { 
		
	}
	
	/** 
	 * Receive digits from DigitsReceiver 
	 * Record called number in CallRecords 
	 * @param lineNum
	 * @return CallProcess 
	 */
	public int DialingPC(int lineNum) { 
		return 0; // temp return value to enable compilation 
	}
	
	/** 
	 * Check called status from CallRecords 
	 * Find available route from Route
	 * Send busy tone to calling if called is busy 
	 * @param lineNum
	 * @return CallProcess
	 */
	public int CheckCalledStatusPC(int lineNum) { 
		int calledNum = callRecordsArray[lineNum].getCalledNum(); 
		if ( (lineScannerArray[calledNum].Status == 2) || 
				(lineScannerArray[calledNum].Status == 3) || 
				(lineScannerArray[calledNum].Status == 4) || 
				(lineScannerArray[calledNum].Status == 5) ) { // hook-off, busy, seized, or invalid
			callRecordsArray[lineNum].setTimer(10); // Set busy tone timer 
			ConnectDrivePC(lineNum, 0, true);
			callRecordsArray[lineNum].setCalledTermination(true); 
			callRecordsArray[lineNum].setTimer(10); 
			callRecordsArray[lineNum].setCallProcess(7); // to exceptional termination
		}
		else { // Status = 0 or Status = 1 
			lineScannerArray[calledNum].Status = 4; 
			callRecordsArray[lineNum].setCallProcess(0);
			// --- insert route seizing --- // 
			
		}
		return 0; // temp return value to enable compilation 
	}
	
	/** 
	 * Send RingBackTone to calling
	 * Send RingingTone to called 
	 * @param lineNum
	 * @return CallProcess 
	 */
	public int ConnectingPC(int lineNum) { 
		return 0; // temp return value to enable compilation 
	}
	
	/** 
	 * When called answered, connect calling-called using pre-seized routes in CallRecords
	 * Process calling give-up
	 * Monitor call termination 
	 * @param lineNum
	 * @return CallProcess 
	 */
	public int TalkingPC(int lineNum) { 
		return 0; // temp return value to enable compilation 
	}
	
	/** 
	 * Process either party termination based on LineScanners
	 * Released routes according to Routes 
	 * Monitor non-hook-on party in CallRecords 
	 * @param lineNum
	 * @return CallProcess 
	 */
	public int CallTerminationPC(int lineNum) {
		int n = lineNum;
		return 0; // temp return value to enable compilation 
	}
	
	/** 
	 * Reset line status in LineScanners, if monitored party hook-on 
	 * If time-out, set line status invalid in LineScanners 
	 * @param lineNum
	 * @return CallProcess 
	 */
	public int ExceptionalTerminationPC(int lineNum) {
		int n = lineNum;
		return 0; // temp return value to enable compilation 
	}
	
	public void L3InterruptPC() { 
		LineScanningPC(); 

	}
	
	public void L4InterruptPC() { 
		SysClockPC(); 
		DigitsReceivingPC(); 
	}

	public SysClock getSysClock() {
		return sysClock;
	}
	
}